package com.fuchun.animloadingprogress;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 加载动画
 */
public class AnimLoadingProgress extends View {

    private final String TAG = "AnimLoadingProgress";

    //进度视图总高度
    private final int proBgHeight = 160;
    //进度高度
    private final int proHeight = 140;
    //视图宽度
    private int viewWidth;
    //视图高度
    private int viewHeight;
    //进度宽度
    private int progressWidth;

    private Paint bgPaint;

    private Paint rightCircleBgPaint;
    private Paint rightCirclePaint;
    //风扇bitmap
    private Paint bitmapPaint;

    private Paint progressPaint;
    private PorterDuffXfermode porterDuffXfermode;
    private Paint duffXferModePaint;

    private Bitmap fanBitmap;
    private Bitmap leafBitmap;

    private int leafWidth;
    private int leafHeight;
    //每个进度多少片叶子
    private int leafPro = 2;

    //源
    private Rect srcRect;
    //位置
    private Rect destRect;
    //风扇旋转度数
    private int fanDegree;
    private int fanSpeed;

    private int maxProgress = 100;
    private int progress = 0;

    private float fanScale = 1;

    private float finishTxtScale;

    private Paint finishTxtPaint;
    private final int txtFontSize = 50;
    private final String finishTxt = "100%";
    private Rect finishTextRect = new Rect();

    private List<Leaf> leafs = new ArrayList<>();

    private Random random;

    private Timer timer = new Timer();


    public AnimLoadingProgress(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        random = new Random();

        bgPaint = new Paint();
        bgPaint.setColor(Color.parseColor("#fcdf93"));
        bgPaint.setStrokeWidth(proBgHeight);
        bgPaint.setStrokeCap(Paint.Cap.ROUND);

        rightCircleBgPaint = new Paint();
        rightCircleBgPaint.setColor(Color.parseColor("#ffffff"));

        rightCirclePaint = new Paint();
        rightCirclePaint.setColor(Color.parseColor("#fccf51"));

        duffXferModePaint = new Paint();
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

        progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        progressPaint.setColor(Color.parseColor("#F5A418"));
        progressPaint.setStyle(Paint.Style.FILL);

        bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bitmapPaint.setFilterBitmap(true);
        bitmapPaint.setDither(true);

        finishTxtPaint = new Paint();
        finishTxtPaint.setAntiAlias(true);//抗锯齿
        finishTxtPaint.setColor(Color.WHITE);
        finishTxtPaint.setStyle(Paint.Style.FILL);
        finishTxtPaint.setTextAlign(Paint.Align.CENTER);

        fanBitmap = ((BitmapDrawable) getResources().getDrawable(R.mipmap.fengshan))
                .getBitmap();
        leafBitmap = ((BitmapDrawable) getResources().getDrawable(R.mipmap.leaf))
                .getBitmap();

        leafWidth = leafBitmap.getWidth();
        leafHeight = leafBitmap.getHeight();

        srcRect = new Rect();
        destRect = new Rect();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (viewWidth == 0 || viewHeight == 0) {
            return;
        } else if (viewHeight < proBgHeight) {
            return;
        }

        //画进度背景
        canvas.drawLine(proBgHeight / 2, viewHeight / 2, viewWidth - proBgHeight / 2, viewHeight / 2, bgPaint);
        //画进度
        drawProgress(canvas);
        //画叶子
        drawLeafs(canvas);
        //画风扇
        drawFan(canvas);
    }

    /**
     * draw progress
     *
     * @param canvas 画布
     */
    private void drawProgress(Canvas canvas) {
        int save = canvas.saveLayer(0, 0, viewWidth, viewHeight, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(drawDestBitmap(), 0, 0, duffXferModePaint);
        duffXferModePaint.setXfermode(porterDuffXfermode);
        canvas.drawBitmap(drawSourceBitmap(), 0, 0, duffXferModePaint);
        duffXferModePaint.setXfermode(null);
        canvas.restoreToCount(save);
    }

    /**
     * draw leafs
     *
     * @param canvas 画布
     */
    private void drawLeafs(Canvas canvas) {
        for (Iterator<Leaf> it = leafs.iterator(); it.hasNext(); ) {
            Leaf leaf = it.next();
            Rect leafRect = leaf.getBitmapRect();
            if (leaf.x + leafWidth < 10 + progressWidth * progress / maxProgress) {
                this.progress += leafPro;
                it.remove();
            } else if (leaf.x < viewWidth - proHeight / 2 && leaf.x > 10) {
                //绘制旋转的bitmap
                drawRotateBitmap(canvas, bitmapPaint, leafBitmap, leaf.getDegree(), leafRect.left, leafRect.top);
            }
        }
    }

    /**
     * draw fan
     * 画风扇
     *
     * @param canvas 画布
     */
    private void drawFan(Canvas canvas) {
        //画进度底层圈
        canvas.drawCircle(viewWidth - proBgHeight / 2, viewHeight / 2, proBgHeight / 2, rightCircleBgPaint);
        //画进度上层圈
        canvas.drawCircle(viewWidth - proBgHeight / 2, viewHeight / 2, proBgHeight / 2 - 10, rightCirclePaint);
        if (fanScale > 0) {
            drawRotateScaleBitmap(canvas, bitmapPaint, fanBitmap, fanDegree, fanScale, destRect.left, destRect.top);
        } else {
            finishTxtPaint.setTextSize(txtFontSize * finishTxtScale);
            finishTxtPaint.getTextBounds(finishTxt, 0, finishTxt.length(), finishTextRect);
            canvas.drawText(finishTxt, viewWidth - proBgHeight / 2, viewHeight / 2 + finishTextRect.height() / 2, finishTxtPaint);
        }

        if (progress == 100 && timer != null) {
            timer.cancel();
            timer = null;
            startFinishAnim();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        viewWidth = getWidth();
        viewHeight = getHeight();

        progressWidth = viewWidth - 20;

        srcRect.set(0, 0, fanBitmap.getWidth(), fanBitmap.getHeight());

        int destRectX = viewWidth - proBgHeight / 2 - fanBitmap.getWidth() / 2;
        int destRectY = viewHeight / 2 - fanBitmap.getHeight() / 2;

        destRect.set(destRectX, destRectY, destRectX + fanBitmap.getWidth(), destRectY + fanBitmap.getWidth());
    }

    /**
     * 绘制旋转图片
     *
     * @param canvas
     * @param paint
     * @param bitmap
     * @param rotation
     * @param posX
     * @param posY
     */
    private void drawRotateBitmap(Canvas canvas, Paint paint, Bitmap bitmap,
                                  float rotation, float posX, float posY) {
        drawRotateScaleBitmap(canvas, paint, bitmap, rotation, 1, posX, posY);
    }

    /**
     * 绘制旋转缩放图片
     *
     * @param canvas
     * @param paint
     * @param bitmap
     * @param rotation
     * @param scale
     * @param posX
     * @param posY
     */
    private void drawRotateScaleBitmap(Canvas canvas, Paint paint, Bitmap bitmap,
                                       float rotation, float scale, float posX, float posY) {
        Matrix matrix = new Matrix();
        int offsetX = bitmap.getWidth() / 2;
        int offsetY = bitmap.getHeight() / 2;
        matrix.postTranslate(-offsetX, -offsetY);
        matrix.postRotate(rotation);
        matrix.postScale(scale, scale);
        matrix.postTranslate(posX + offsetX, posY + offsetY);
        canvas.drawBitmap(bitmap, matrix, paint);
    }

    /**
     * 画原始的bitmap
     *
     * @return 原bitmap
     */
    private Bitmap drawSourceBitmap() {
        Bitmap bm = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bm);
        canvas.drawRoundRect(new RectF(10, viewHeight / 2 - proHeight / 2, progressWidth, viewHeight / 2 + proHeight / 2), proHeight / 2, proHeight / 2, progressPaint);
        return bm;
    }


    /**
     * 画目标的bitmap
     *
     * @return 目标bitmap
     */
    private Bitmap drawDestBitmap() {
        Bitmap bm = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bm);
        canvas.drawRect(new Rect(10, viewHeight / 2 - proHeight / 2, 10 + (progressWidth) * progress / maxProgress, viewHeight / 2 + proHeight / 2), progressPaint);
        return bm;
    }

    /**
     * 启动加载
     */
    public void startLoading() {
        progress = 0;
        fanScale = 1;
        finishTxtScale = 0;

        timer = new Timer();
        timer.schedule(new AnimLoadingTask(), 0, 40);
    }

    /**
     * 设置进度
     *
     * @param progress 设置进度
     */
    public void setProgress(int progress) {
        int rate = progress - (this.progress + leafs.size() * 2);
        if (rate < 2) {
            return;
        }

        fanSpeed = rate * 5;
        createLeaf(rate / leafPro);
    }

    /**
     * 创建叶片
     *
     * @param count 数量
     */
    public void createLeaf(int count) {
        for (int i = 0; i < count; i++) {
            leafs.add(new Leaf());
        }
    }

    /**
     * 启动完成动画
     */
    public void startFinishAnim() {
        ValueAnimator anim = ValueAnimator.ofFloat(1, 0);
        anim.setDuration(500);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                fanScale = (Float) animation.getAnimatedValue();
                postInvalidate();
                if (fanScale == 0) {
                    startFinishTxtAnim();
                }
            }
        });
        anim.start();
    }

    /**
     * 启动完成文案动画
     */
    public void startFinishTxtAnim() {
        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
        anim.setDuration(500);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                finishTxtScale = (Float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        anim.start();
    }

    class AnimLoadingTask extends TimerTask {
        @Override
        public void run() {
            fanDegree -= fanSpeed;
            AnimLoadingProgress.this.postInvalidate();
        }
    }

    class Leaf {
        private int x;
        private int cycle;
        private int y;
        private int degree;
        private int degreeSpeed;
        private int amplitude;

        Leaf() {
            x = viewWidth - proHeight / 2 + (int) (random.nextFloat() * progressWidth / 4);
            cycle = progressWidth / 2 + (int) (random.nextFloat() * progressWidth / 2);
            degreeSpeed = (int) (random.nextBoolean() ? 4 : -4 * random.nextFloat());
            degree = (int) (random.nextFloat() * 360);
            amplitude = (int) ((proHeight / 2 - leafHeight) * random.nextFloat());
        }

        private int getY() {
            return (int) (amplitude * Math.sin(2 * Math.PI / cycle * x)) + viewHeight / 2 - leafHeight / 2;
        }

        private Rect getBitmapRect() {
            x -= 10;
            y = getY();
            return new Rect(x, y, x + leafBitmap.getWidth(), y + leafBitmap.getHeight());
        }

        public int getDegree() {
            degree += degreeSpeed;
            return degree;
        }
    }
}
